/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/***************************************************************************************************
 *  \file     AnaCtrl_IP.h                                                                         *
 *  \brief    This file contains interface header for Analog Control low level driver.             *
 *                                                                                                 *
 * <table>                                                                                         *
 * <tr><th>Date           <th>Version                                                              *
 * <tr><td>2025/2/11      <td>1.0.0                                                                *
 * </table>                                                                                        *
 **************************************************************************************************/

#ifndef ANACTRL_IP_H
#define ANACTRL_IP_H

/***************************************************************************************************
 *                                      Include header files                                       *
 **************************************************************************************************/

#include <lld_platform.h>

#ifdef __cplusplus
extern "C" {
#endif

/***************************************************************************************************
 *                                 Global Macro definition                                         *
 **************************************************************************************************/

/** \brief Register address offset. */
#define ANA_CTRL_DAC_BUF_CTRL           (0x10u)
#define ANA_CTRL_DAC_PWR_CTRL           (0x20u)
#define ANA_CTRL_ATE_TEST_CFG           (0x40u)
#define ANA_CTRL_APD_A0                 (0x3000u)
#define ANA_CTRL_AMUX_REF               (0x4800u)
#define ANA_CTRL_ADC_SYNC               (0x7000u)

/** \brief Register bit definitions. */
#define ANA_CTRL_DAC_BUF_CTRL_BYPASS    (1u << 0)
#define ANA_CTRL_DAC_BUF_CTRL_ATESTO    (1u << 3)

#define ANA_CTRL_DAC_PWR_CTRL_DOWN      (1u << 0)

#define ANA_CTRL_ATE_TEST_CFG_REF_SEL2  (1u << 0)
#define ANA_CTRL_ATE_TEST_CFG_DATA_POS  4
#define ANA_CTRL_ATE_TEST_CFG_DATA_WIDTH    12

#define ANA_CTRL_APD_A_IN               (1u << 0)
#define ANA_CTRL_APD_A_SPD              (1u << 1)
#define ANA_CTRL_APD_A_WPD              (1u << 2)
#define ANA_CTRL_APD_A_WPU              (1u << 3)
#define ANA_CTRL_APD_A_WIDTH            (4u)
#define ANA_CTRL_APD_A_MSK              ((1u << ANA_CTRL_APD_A_WIDTH) - 1)

#define ANA_CTRL_AMUX_REF_CSEL_POS      0
#define ANA_CTRL_AMUX_REF_CSEL_MSK      (0xFu << ANA_CTRL_AMUX_REF_CSEL_POS)

#define ANA_CTRL_ADC_SYNC_EN            (1u << 0)
#define ANA_CTRL_ADC_SYNC_CLK_SEL(n)    (1u << (n))
#define ANA_CTRL_ADC_SYNC_NBR_MAX       (6u)
#define ANA_CTRL_ADC_SYNC_CLK_SEL_MSK   (0x3Fu << 1)


/***************************************************************************************************
 *                                  Global Types definition                                        *
 **************************************************************************************************/

/** \brief Cross Reference for analog pins and their registers. */
typedef enum AnaCtrl_ApdA {
    ANA_CTRL_APD_A_A0   = 0,
    ANA_CTRL_APD_A_A1,
    ANA_CTRL_APD_A_A2,
    ANA_CTRL_APD_A_A3,
    ANA_CTRL_APD_A_A4,
    ANA_CTRL_APD_A_A5,
    ANA_CTRL_APD_A_A6,
    ANA_CTRL_APD_A_A7,
    ANA_CTRL_APD_A_A8,
    ANA_CTRL_APD_A_A9,
    ANA_CTRL_APD_A_A10,
    ANA_CTRL_APD_A_A11,
    ANA_CTRL_APD_A_A12,
    ANA_CTRL_APD_A_A13,
    ANA_CTRL_APD_A_A14,
    ANA_CTRL_APD_A_A15,

    ANA_CTRL_APD_A_B0,
    ANA_CTRL_APD_A_B1,
    ANA_CTRL_APD_A_B2,
    ANA_CTRL_APD_A_B3,
    ANA_CTRL_APD_A_B4,
    ANA_CTRL_APD_A_B5,
    ANA_CTRL_APD_A_B6,
    ANA_CTRL_APD_A_B7,
    ANA_CTRL_APD_A_B8,
    ANA_CTRL_APD_A_B9,
    ANA_CTRL_APD_A_B10,
    ANA_CTRL_APD_A_B11,
    ANA_CTRL_APD_A_B12,
    ANA_CTRL_APD_A_B13,
    ANA_CTRL_APD_A_B14,
    ANA_CTRL_APD_A_B15,

    ANA_CTRL_APD_A_C0,
    ANA_CTRL_APD_A_C1,
    ANA_CTRL_APD_A_C2,
    ANA_CTRL_APD_A_C3,
    ANA_CTRL_APD_A_C4,
    ANA_CTRL_APD_A_C5,
    ANA_CTRL_APD_A_C6,
    ANA_CTRL_APD_A_C7,
    ANA_CTRL_APD_A_C8,
    ANA_CTRL_APD_A_C9,
    ANA_CTRL_APD_A_C10,
    ANA_CTRL_APD_A_C11,
    ANA_CTRL_APD_A_C12,
    ANA_CTRL_APD_A_C13,
    ANA_CTRL_APD_A_C14,
    ANA_CTRL_APD_A_C15,

    ANA_CTRL_APD_A_K0,
    ANA_CTRL_APD_A_K1,
    ANA_CTRL_APD_A_K2,
    ANA_CTRL_APD_A_K3,
    ANA_CTRL_APD_A_K4,
    ANA_CTRL_APD_A_K5,
    ANA_CTRL_APD_A_K6,
    ANA_CTRL_APD_A_K7,
    ANA_CTRL_APD_A_K8,
    ANA_CTRL_APD_A_K9,
    ANA_CTRL_APD_A_K10,
    ANA_CTRL_APD_A_K11,
    ANA_CTRL_APD_A_K12,
    ANA_CTRL_APD_A_K13,
    ANA_CTRL_APD_A_K14,
    ANA_CTRL_APD_A_K15,
    ANA_CTRL_APD_A_K16,
    ANA_CTRL_APD_A_K17,
    ANA_CTRL_APD_A_K18,
    ANA_CTRL_APD_A_K19,
    ANA_CTRL_APD_A_K20,
    ANA_CTRL_APD_A_K21,
    ANA_CTRL_APD_A_K22,
    ANA_CTRL_APD_A_K23,

    ANA_CTRL_APD_A_U0,
    ANA_CTRL_APD_A_U1,
    ANA_CTRL_APD_A_U2,
    ANA_CTRL_APD_A_U3,
    ANA_CTRL_APD_A_U4,
    ANA_CTRL_APD_A_U5,
    ANA_CTRL_APD_A_U6,
    ANA_CTRL_APD_A_U7,
    ANA_CTRL_APD_A_U8,
    ANA_CTRL_APD_A_U9,
    ANA_CTRL_APD_A_U10,
    ANA_CTRL_APD_A_U11,
    ANA_CTRL_APD_A_U12,
    ANA_CTRL_APD_A_U13,
    ANA_CTRL_APD_A_U14,
    ANA_CTRL_APD_A_U15,
    ANA_CTRL_APD_A_U16,
    ANA_CTRL_APD_A_U17,
    ANA_CTRL_APD_A_U18,
    ANA_CTRL_APD_A_U19,
    ANA_CTRL_APD_A_U20,
    ANA_CTRL_APD_A_U21,
    ANA_CTRL_APD_A_U22,
    ANA_CTRL_APD_A_U23,

    ANA_CTRL_APD_A_CNT
} AnaCtrl_ApdAType;

/** \brief Analog Mux for ADC CH7P. */
typedef enum AnaCtrl_AdcCh7pMux {
    ADC_CH7P_MUX_DAC1_O,
    ADC_CH7P_MUX_DAC2_O,
    ADC_CH7P_MUX_ATEST,
    ADC_CH7P_MUX_VDD_SF,
    ADC_CH7P_MUX_VDD_LP,
    ADC_CH7P_MUX_GND1,
    ADC_CH7P_MUX_GND2,
    ADC_CH7P_MUX_AVDD_LADC,
} AnaCtrl_AdcCh7pMuxType;

/** \brief Analog Mux for ADC CH7N. */
typedef enum AnaCtrl_AdcCh7nMux {
    ADC_CH7N_MUX_DAC1_O,
    ADC_CH7N_MUX_DAC2_O,
    ADC_CH7N_MUX_GND1,
    ADC_CH7N_MUX_VDD_SF,
    ADC_CH7N_MUX_VDD_LP,
    ADC_CH7N_MUX_GND2,
    ADC_CH7N_MUX_GND3,
    ADC_CH7N_MUX_AVDD_SADC,
} AnaCtrl_AdcCh7nMuxType;

/** \brief DAC reference voltage. AVDD_SADC50 or VREF_SADC. */
typedef enum AnaCtrl_DacRefSel {
    DAC_REF_SEL_P1,
    DAC_REF_SEL_AVDD_SADC50 = DAC_REF_SEL_P1,
    DAC_REF_SEL_P2,
    DAC_REF_SEL_VREF_SADC = DAC_REF_SEL_P2,
} AnaCtrl_DacRefSelType;


/***************************************************************************************************
 *                                  Global Function Declarations                                   *
 **************************************************************************************************/

/***************************************************************************************************
 * \brief Configure APD_A of the specified analog pad.
 *
 * \verbatim
 * Syntax             : void AnaCtrl_SetApdA(uint32_t AnaCtrlBase,
 *                                           AnaCtrl_ApdAType apdIdx,
 *                                           unsigned int apdACfg)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Reentrant
 *
 * Parameters (in)    : AnaCtrlBase - Base address of analog control
 *                      apdIdx - Register index of the analog pad
 *                      apdACfg - APD_A value to be configured
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Configure APD_A of the specified analog pad, only for SF pins.
 * \endverbatim
 **************************************************************************************************/
static inline
void AnaCtrl_SetApdA(uint32_t AnaCtrlBase, AnaCtrl_ApdAType apdIdx, unsigned int apdACfg)
{
    uint32_t reg_addr = AnaCtrlBase + ANA_CTRL_APD_A0 + apdIdx * sizeof(uint32_t);

    writel(apdACfg, reg_addr);
}

/***************************************************************************************************
 * \brief Enable or disable ADC clock sync.
 *
 * \verbatim
 * Syntax             : void AnaCtrl_SetAdcSync(uint32_t AnaCtrlBase, unsigned int enable)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : AnaCtrlBase - Base address of analog control
 *                      enable - Enable ADC clock sync or not
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Enable or disable ADC clock sync.
 * \endverbatim
 **************************************************************************************************/
static inline
void AnaCtrl_SetAdcSync(uint32_t AnaCtrlBase, unsigned int enable)
{
    uint32_t reg_addr = AnaCtrlBase + ANA_CTRL_ADC_SYNC;
    uint32_t temp;

    temp = readl(reg_addr);
    if (enable) {
        temp |= ANA_CTRL_ADC_SYNC_EN;
    } else {
        temp &= ~ANA_CTRL_ADC_SYNC_EN;
    }
    writel(temp, reg_addr);
}

/***************************************************************************************************
 * \brief Select clock source for multiple ADC.
 *
 * \verbatim
 * Syntax             : void AnaCtrl_SetAdcClkSel(uint32_t AnaCtrlBase, unsigned int clkSelFlags)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : AnaCtrlBase - Base address of analog control
 *                      clkSelFlags - A group of bits defined by ANA_CTRL_ADC_SYNC_CLK_SEL(n).
 *                                      Bit1~bit6 correspond to ADC1~ADC6. ADC7 is not supported.
 *                                      Bit value 1 selects buffered ADC1 clock for an ADC.
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Select clock source for multiple ADC.
 * \endverbatim
 **************************************************************************************************/
static inline
void AnaCtrl_SetAdcClkSel(uint32_t AnaCtrlBase, unsigned int clkSelFlags)
{
    uint32_t reg_addr = AnaCtrlBase + ANA_CTRL_ADC_SYNC;
    uint32_t temp;

    temp = readl(reg_addr);
    temp &= ~ANA_CTRL_ADC_SYNC_CLK_SEL_MSK;
    temp |= clkSelFlags;
    writel(temp, reg_addr);
}

/***************************************************************************************************
 * \brief Select signal source for ADC CH7P.
 *
 * \verbatim
 * Syntax             : void AnaCtrl_SetAdcCh7pMux(uint32_t AnaCtrlBase, AnaCtrl_AdcCh7pMuxType mux)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : AnaCtrlBase - Base address of analog control
 *                      mux - Select signal input of the multiplexer
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Select signal source for ADC CH7P.
 * \endverbatim
 **************************************************************************************************/
static inline
void AnaCtrl_SetAdcCh7pMux(uint32_t AnaCtrlBase, AnaCtrl_AdcCh7pMuxType mux)
{
    uint32_t reg_addr = AnaCtrlBase + ANA_CTRL_AMUX_REF;
    uint32_t temp;

    temp = readl(reg_addr);
    temp &= ~ANA_CTRL_AMUX_REF_CSEL_MSK;
    temp |= mux << ANA_CTRL_AMUX_REF_CSEL_POS;
    writel(temp, reg_addr);
}

/***************************************************************************************************
 * \brief Select signal source for ADC CH7N.
 *
 * \verbatim
 * Syntax             : void AnaCtrl_SetAdcCh7nMux(uint32_t AnaCtrlBase, AnaCtrl_AdcCh7nMuxType mux)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : AnaCtrlBase - Base address of analog control
 *                      mux - Select signal input of the multiplexer
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Select signal source for ADC CH7N.
 * \endverbatim
 **************************************************************************************************/
static inline
void AnaCtrl_SetAdcCh7nMux(uint32_t AnaCtrlBase, AnaCtrl_AdcCh7nMuxType mux)
{
    uint32_t reg_addr = AnaCtrlBase + ANA_CTRL_AMUX_REF + sizeof(uint32_t);
    uint32_t temp;

    temp = readl(reg_addr);
    temp &= ~ANA_CTRL_AMUX_REF_CSEL_MSK;
    temp |= mux << ANA_CTRL_AMUX_REF_CSEL_POS;
    writel(temp, reg_addr);
}

/***************************************************************************************************
 * \brief Enable or disable DAC output buffer.
 *
 * \verbatim
 * Syntax             : void AnaCtrl_SetDacBuffer(uint32_t AnaCtrlBase, unsigned int dacIdx,
 *                                                                          unsigned int enable)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : AnaCtrlBase - Base address of analog control
 *                      dacIdx - DAC index [0, 1]
 *                      enable - Enable buffer or not. It must be 1 currently.
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Enable or disable DAC output buffer.
 * \endverbatim
 **************************************************************************************************/
static inline
void AnaCtrl_SetDacBuffer(uint32_t AnaCtrlBase, unsigned int dacIdx, unsigned int enable)
{
    uint32_t reg_addr = AnaCtrlBase + ANA_CTRL_DAC_BUF_CTRL + dacIdx * sizeof(uint32_t);
    uint32_t temp;

    temp = readl(reg_addr);
    if (enable) {
        temp &= ~ANA_CTRL_DAC_BUF_CTRL_BYPASS;
    } else {
        temp |= ANA_CTRL_DAC_BUF_CTRL_BYPASS;
    }
    writel(temp, reg_addr);
}

/***************************************************************************************************
 * \brief Power on DAC to work, or power down it.
 *
 * \verbatim
 * Syntax             : void AnaCtrl_SetDacPower(uint32_t AnaCtrlBase, unsigned int dacIdx,
 *                                                                          unsigned int powerOn)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : AnaCtrlBase - Base address of analog control
 *                      dacIdx - DAC index [0, 1]
 *                      powerOn - true to power on DAC
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Power on DAC to work, or power down it.
 * \endverbatim
 **************************************************************************************************/
static inline
void AnaCtrl_SetDacPower(uint32_t AnaCtrlBase, unsigned int dacIdx, unsigned int powerOn)
{
    uint32_t reg_addr = AnaCtrlBase + ANA_CTRL_DAC_PWR_CTRL + dacIdx * sizeof(uint32_t);
    uint32_t temp;

    temp = readl(reg_addr);
    if (powerOn) {
        temp &= ~ANA_CTRL_DAC_PWR_CTRL_DOWN;
    } else {
        temp |= ANA_CTRL_DAC_PWR_CTRL_DOWN;
    }
    writel(temp, reg_addr);
}

/***************************************************************************************************
 * \brief Set DAC output voltage.
 *
 * \verbatim
 * Syntax             : void AnaCtrl_SetDacOutput(uint32_t AnaCtrlBase,
 *                                                unsigned int dacIdx,
 *                                                unsigned int value,
 *                                                AnaCtrl_DacRefSelType ref)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Reentrant
 *
 * Parameters (in)    : AnaCtrlBase - Base address of analog control
 *                      dacIdx - DAC index [0, 1]
 *                      value - Digital value of the output voltage
 *                      ref - Select reference voltage
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Set DAC output voltage. The output voltage is
 *                          (reference voltage) * value / 4096.
 * \endverbatim
 **************************************************************************************************/
static inline
void AnaCtrl_SetDacOutput(uint32_t AnaCtrlBase,
                          unsigned int dacIdx,
                          unsigned int value,
                          AnaCtrl_DacRefSelType ref)
{
    uint32_t reg_addr = AnaCtrlBase + ANA_CTRL_ATE_TEST_CFG + dacIdx * sizeof(uint32_t);
    uint32_t reg_cfg;

    reg_cfg = value << ANA_CTRL_ATE_TEST_CFG_DATA_POS;
    if (ref == DAC_REF_SEL_P2) {
        reg_cfg |= ANA_CTRL_ATE_TEST_CFG_REF_SEL2;
    }
    writel(reg_cfg, reg_addr);
}


#ifdef __cplusplus
}
#endif


#endif  /* #ifndef ANACTRL_IP_H */

/* End of file */

